package com.jysz.certificate.service.workflow;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;

import com.jysz.certificate.persistence.dao.system.OrganizationDao;
import com.jysz.certificate.persistence.dao.system.UserDao;
import com.jysz.certificate.persistence.dao.workflow.WorkflowDao;
import com.jysz.certificate.persistence.enums.OrganizationEnum;
import com.jysz.certificate.persistence.enums.PostType;
import com.jysz.certificate.persistence.enums.WorkflowOperateType;
import com.jysz.certificate.persistence.enums.WorkflowState;
import com.jysz.certificate.persistence.enums.WorkflowType;
import com.jysz.certificate.persistence.model.system.Organization;
import com.jysz.certificate.persistence.model.system.User;
import com.jysz.certificate.persistence.model.workflow.Workflow;
import com.jysz.certificate.persistence.model.workflow.WorkflowObject;
import com.jysz.certificate.utils.CommonUtil;
import com.jysz.webcore.exceptions.WebSystemException;
import com.jysz.webcore.ssh.orm.hibernate.support.Page;
import com.jysz.webcore.ssh.service.EntityService;

/**
 * 工作流程
 * 
 * @author xuxiaolong
 */
@Service
public class WorkflowService extends EntityService<Workflow, Long, WorkflowDao> {

	@Resource
	private WorkflowDao workflowDao;
	@Resource
	private OrganizationDao organDao;
	@Resource
	private UserDao userDao;
	
	@Override
	public WorkflowDao getEntityDao() {
		return this.workflowDao;
	}

	/**
	 * 根据对象ID获得关联的流程
	 * @param type
	 * @param objId
	 * @return
	 */
	public Workflow find(WorkflowType type,Long objId){
		return workflowDao.find(type,objId);
	}
	
	/**
	 * 查询流程
	 * @param userId 发起人
	 * @return
	 */
	public Page<Workflow> findPage(User currentUser,Workflow wf, int pageNo, int pageSize) {
		Criteria criteria = workflowDao.createCriteria();
		criteria.addOrder(Order.asc(Workflow.STATE));
		criteria.addOrder(Order.desc(Workflow.CREATED_AT));

		if (wf != null) {
			if(wf.getSponsor()!=null&&CommonUtil.isNotEmpty(wf.getSponsor().getRealName()))
				criteria.createCriteria("sponsor").add(Restrictions.like("realName", wf.getSponsor().getRealName(), MatchMode.ANYWHERE));
			if(wf.getType()!=null)
				criteria.add(Restrictions.eq("type", wf.getType()));
			if(wf.getState()!=null)
				criteria.add(Restrictions.eq("state", wf.getState()));
			
			//发起日期-开始
			if(wf.getCreatedAt()!=null)
				criteria.add(Restrictions.ge("createdAt", wf.getCreatedAt()));
			//发起日期-结束
			if(wf.getUpdatedAt()!=null)
				criteria.add(Restrictions.le("createdAt", wf.getUpdatedAt()));
		}
		
		//根据发起人来添加权限过滤 (查找当前用户在组织架构中所管理的其他用户)
		if(currentUser.getPost().compareTo(PostType.Admin)!=0){
			Set<User> users=new HashSet<User>();
			List<Organization> orgList=organDao.findOrgByUser(currentUser);
			if(orgList!=null){
				for(Organization org:orgList){
					Organization parent = org.getParent();
					getChildUsers(parent.getChilds(), users);
				}
			}
			if(users.size()>0)
				criteria.add(Restrictions.in("sponsor", users));
			else
				criteria.add(Restrictions.sqlRestriction("1 != 1"));
		}
		
		return this.findPage(criteria, pageNo, pageSize);
	}

	public void getChildUsers(List<Organization> orgList,Set<User> users){
		for(Organization org:orgList){
			if(org.getType().compareTo(OrganizationEnum.STAFF)==0){
				users.add(userDao.find(org.getObjectId()));
			}else if(org.getChilds()!=null){
				getChildUsers(org.getChilds(),users);
			}
				
		}
	}
	
	/** 添加新流程 */
	public void addNewWorkflow(User currentUser, WorkflowType type,
			Class objClass, Long[] ids) {

		Workflow wf = new Workflow();
		wf.setSponsor(currentUser);// 发起人，即当前用户
		wf.setState(WorkflowState.NOTSTART);// 未开始
		wf.setType(type);// 流程类型
		wf.setObjType(objClass);// 关联对象的Class

		wf.setObjects(Workflow.buildWfObjects(wf, ids));// 关联的对象

		this.save(wf);
		

	}
	
	/**
	 * 发起新流程
	 * @param currentUser发起人
	 * @param id 关联对象ID
	 * @param state 发起后流程的状态
	 * @param type 流程类型
	 * @param cls  关联对象的Class
	 * @param msg  操作记录(eg.提交释放单流程)
	 */
	public void addWorkflow(User currentUser,Long id,WorkflowState state,WorkflowType type,Class cls,String msg){
		
		Workflow wf=new Workflow(currentUser,state,type,cls,new Long[]{id});
		//构建操作记录
		Workflow.buildOperates(wf, currentUser,WorkflowOperateType.SUBMIT,msg);
		
		workflowDao.save(wf);
	}
	
	/**
	 * 更改流程状态 并添加操作记录
	 * @param wf   当前操作流程
	 * @param state 希望将流程改为什么状态
	 * @param operateType 操作类型
	 * @param msg 审核意见
	 * @param msg
	 */
	public void audit(User currentUser,Workflow wf,WorkflowState state,WorkflowOperateType operateType,String msg){
		wf.setState(state);
		Workflow.buildOperates(wf, currentUser,operateType,msg);
		workflowDao.save(wf);
		
	}

	// 审核
	public void audit(Long wfId, Long[] ids, WorkflowOperateType wfo) {
		if (wfId == null || ids == null || wfo == null)
			return;
		Workflow wf = super.find(wfId);
		List objects = wf.getObjects();
		if (objects.size() == ids.length) {
			if (wfo.compareTo(WorkflowOperateType.PASS) == 0) {
				wf.setState(WorkflowState.FINISH);
			} else {
				wf.setState(WorkflowState.REFUSED);
			}
			this.save(wf);
		} else {
			this.split(wf, ids, wfo);
		}
	}

	/**
	 * 拆分流程
	 * 
	 * @param wfId
	 *            原流程ID
	 * @param ids
	 *            选中的ids
	 * @param wfo
	 *            操作：同意/退回
	 */
	public void split(Workflow wf, Long[] ids, WorkflowOperateType wfo) {
		Workflow newWf = new Workflow();
		newWf.setSponsor(wf.getSponsor());// 发起人
		newWf.setType(wf.getType());// 流程类型
		newWf.setObjType(wf.getObjType());// 关联对象的Class
		// 通过
		if (wfo.compareTo(WorkflowOperateType.PASS) == 0) {
			// 原流程只保留选中ids,剩下的id放到新流程.新流程状态为待审核
			this.buildSplitObject(wf,newWf,wf.getObjects(),ids);
			newWf.setState(WorkflowState.SUBMITED);// 待审核
		}
		// 退回
		else if (wfo.compareTo(WorkflowOperateType.REFUSE) == 0) {
			// 原流程只保留未被选中的id(即除了ids以外的).新流程的ids即为选中的ids,状态为已退回
			this.buildSplitObject(newWf,wf,wf.getObjects(),ids);
			newWf.setState(WorkflowState.REFUSED);// 待审核
		}
		wf.setSplitWorkflow(newWf);
		wf.setState(WorkflowState.FINISH);// 原流程状态更改为已完成
		this.save(wf);

	}

	private void buildSplitObject(Workflow wf1,Workflow wf2,List<WorkflowObject>all, Long[] ids) {
		List<WorkflowObject> checked =new ArrayList<WorkflowObject>();
		List<WorkflowObject> unchecked =new ArrayList<WorkflowObject>();
		Long tmpId = null;
		String ary = buildAryStr(ids);
		for (WorkflowObject wfo : all) {
			tmpId = wfo.getObjectId();
			if (exist(ary, tmpId)) {
				wfo.setWorkflow(wf1);
				checked.add(wfo);// 将选中的加入已选中集合checked
			}else{
				wfo.setWorkflow(wf2);
				unchecked.add(wfo);// 将未选中的加入未选中集合unchecked
			}
		}
		
	}

	private boolean exist(String ids, Long tmp) {
		if (ids == null || tmp == null)
			return false;
		if (ids.indexOf("-" + tmp.toString()) != -1)
			return true;
		return false;

	}

	private String buildAryStr(Long[] ary) {
		StringBuilder sb = new StringBuilder();
		for (Long l : ary) {
			sb.append("-").append(l.toString());
		}
		return sb.toString();
	}

	/**
	 * 删除相关流程。
	 * 
	 * @param objectId
	 * @param renew
	 */
	public void destory(Long objectId, WorkflowType type) {
		Workflow wf = this.find(type, objectId);
		
		if(wf != null){
			if(WorkflowState.isCanDelete(wf.getState())){
				this.destory(wf);
			}else{
				throw new WebSystemException("流程状态不允许被删除。。。");
			}
			
		}
	}
}
